package ua.com.softway.mail;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import java.util.Properties;

import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import ua.com.softway.date.DatePattern;
import ua.com.softway.date.DateTime;

import com.sun.mail.pop3.POP3SSLStore;

public class SmtpTester extends Thread {
    private final static Logger log = Logger.getLogger(SmtpTester.class);
    
    private final Config config;
    
    public SmtpTester(Config config) {
        this.config = config;
    }
    
    private final TransactionControl transactionControl = new TransactionControl();
    
    @Override
    public void run() {
        while (true) {
            transactionControl.begin();
            
            TestMessage lastMessage = new TestMessage();
            lastMessage.send();
            
            transactionControl.commit();
            
            Mailer.notifyMailer();
            
            timeDelta = 0;
            
            while (!foundInMailBox(lastMessage)) {
                timeDelta = DateTime.now().getUTC() - lastMessage.date.getUTC();
                
                try {
                    Thread.sleep(30 * 1000);
                } catch (InterruptedException e) {
                    return;
                }
            }
            
            timeDelta = DateTime.now().getUTC() - lastMessage.date.getUTC();
            
            log.debug("Test message found, timeDelta=" + timeDelta);
            
            secondsToDeliver = timeDelta / 1000.0;
            
            try {
                Thread.sleep(config.delayBetweenMessages * 60 * 1000);
            } catch (InterruptedException e) {
                return;
            }
        }
    }
    
    long timeDelta = 0;
    
    private boolean foundInMailBox(TestMessage lastMessage) {
        Store store = null;

        boolean received = false;
        
        try {
            store = getStore();
            store.connect();

            Folder folder = store.getDefaultFolder();
            folder = folder.getFolder("INBOX");

            folder.open(Folder.READ_WRITE);

            for (Message message : folder.getMessages()) {
                message.setFlag(Flags.Flag.DELETED, true);
                
                received = received || lastMessage.received(message);
            }

            folder.close(true);
        } catch (MessagingException e) {
            log.warn("Can't fetch messages: " + e.getMessage());
        } finally {
            if (store != null)
                try {
                    store.close();
                } catch (MessagingException e) { }
        }
        
        return received;
    }
    
    private Store getStore() {
        Properties props = new Properties();

        if (config.pop3port != null) {
            props.put("mail.pop3.port", "995");
            props.put("mail.pop3.socketFactory.port", "995");
        }
        
        if (config.pop3ssl) {
            if (config.pop3port == null) throw new RuntimeException("If SSL is used, server port should be specified");
            
            props.put("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        
            props.put("mail.pop3.socketFactory.fallback", "false"); // ?

            URLName url = new URLName("pop3", config.pop3host, config.pop3port, "", config.login, config.password);

            Session session = Session.getInstance(props, null);

            return new POP3SSLStore(session, url);
        } else {
            throw new RuntimeException("Only SSL connection is implemented");
        }
    }

    
    class TestMessage extends MailMessage {
        private final DateTime date = DateTime.now();
        private final DatePattern datePattern = new DatePattern("dd.MM.yyyy HH:mm");
        
        @Override
        public String getBody() {
            return datePattern.format(date);
        }

        public boolean received(Message message) {
            try {
                String subject = message.getSubject();
                
                if (!subject.startsWith("TestSmtp,")) return false;
                
                String date = subject.substring("TestSmtp,".length());
            
                return date.equals(datePattern.format(this.date));
            } catch (MessagingException e) {
            }
            
            return false;
        }

        @Override
        public String getSubject() {
            return "TestSmtp," + datePattern.format(date);
        }
        
        @Override
        public String getTo() {
            return config.mailBox;
        }
        
        @Override
        public void send() {
            super.send();
            
            log.debug("Sent test message");
        }
        
        @Override
        public int getPriority() {
            return config.priority;
        }

    }
    
    public double secondsToDeliver = 0;
    
    public class SmtpDelayServlet extends HttpServlet {
        DecimalFormat f = new DecimalFormat("#.##");
        { f.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US)); }
        
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/plain");
            
            PrintWriter writer = resp.getWriter();
            
            writer.println(f.format(secondsToDeliver));
        }
    }
    
    public static class Config {
        public String mailBox = "4k.smpttest@gmail.com";
        public int delayBetweenMessages = 10; // one in a 10 minutes, 144 letters a day
        
        public String login = "4k.smpttest";
        public String password = "d5utREdR";
        public String pop3host = "pop.gmail.com";
        public Integer pop3port = 995;
        public boolean pop3ssl = true;
        
        public int priority = 10;
    }
}
